#rgePog - for the Random Game Generator project
#
#By Doctus (kirikayuumura.noir@gmail.com)
'''
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
'''
from PyQt4 import QtGui
import rgeTile, rgeSystem, math, rgeSprite, rgeEvent, rgeViews


class SpriteTile(object):
    '''Tile shown in sprite editor'''

    def __init__(self, Sprite, currentAni, currentFrame):
        self.tile = None
        self.update(Sprite, currentAni, currentFrame)

        self.beingDragged = False
        self.dragX = 0
        self.dragY = 0

        self.draw()

        rgeEvent.addMousePressListener(self)
        rgeEvent.addMouseMoveListener(self)
        rgeEvent.addMouseReleaseListener(self)

    def update(self, Sprite, currentAni, currentFrame):
        self.texture = Sprite.getTextureAniPath(currentAni, currentFrame)
        self.textureFrame = Sprite.getTextureValues(currentAni, currentFrame)
        self.textureDimensions = Sprite.getTextureAniSplit(currentAni, currentFrame)
        self.mapPos = Sprite.getOffset(currentAni, currentFrame)
        self.flip = Sprite.getFlip(currentAni, currentFrame)
        self.size = Sprite.getSize(currentAni, currentFrame)
        self.center = Sprite.getCenter(currentAni, currentFrame);

        self.draw()


    def move(self, newX, newY):
        self.mapPos = [newX, newY]
        self.draw()

    def setSize(self, newX, newY):
        self.size = [newX, newY]
        self.draw()

    def setTexture(self, newTexPath):
        self.texture = newTexPath
        self.draw()

    def setTextureFrame(self, newX, newY):
        self.textureFrame = [newX, newY]
        self.draw()

    def setTextureDimen(self, newX, newY):
        self.textureDimensions = [newX, newY]
        self.draw()

    def draw(self):
        if self.tile:
            self.deleteTile()
        self.tile = self._makeTile()


    def getTilesize(self):
        from rgeSystem import mainWindow
        size = mainWindow.glwidget.getImageSize(self.texture)
        return [size.width() / self.textureDimensions[0], size.height() / self.textureDimensions[1]]

    def getArea(self):
        tilesize = self.getTilesize()
        if self.center:
            mappos = [self.mapPos[0] - (((tilesize[0] * self.size[0]) - tilesize[0]) / 2), self.mapPos[1] - (((tilesize[1] * self.size[1]) - tilesize[1]) / 2)]
            mappos2 = [tilesize[0] * self.size[0],tilesize[1] * self.size[1]]
        else:
            mappos = [self.mapPos[0] * self.size[0], self.mapPos[1] * self.size[1]]
            mappos2 = [((self.mapPos[0] + tilesize[0]) * self.size[0]) - mappos[0], ((self.mapPos[1] + tilesize[1]) * self.size[1]) - mappos[1]]
        drawRect = [0,0,0,0]
        drawRect[0] = mappos[0]
        drawRect[2] = mappos2[0]
        drawRect[1] = mappos[1]
        drawRect[3] = mappos2[1]
        return drawRect



    def _makeTile(self):
        if len(self.texture) == 0:
            return None
        from rgeSystem import mainWindow
        tilesize = self.getTilesize()
        pos = [tilesize[0] * (self.textureFrame[0] - 1), tilesize[1] * (self.textureFrame[1] - 1)]
        pos2 = [tilesize[0], tilesize[1]]
        textureRect = [0,0,1,1]
        if not self.flip[0]:
            textureRect[0] = pos[0]
            textureRect[2] = pos2[0]
        else:
            textureRect[0] = pos[0] + tilesize[0]
            textureRect[2] = -pos2[0]
        if not self.flip[1]:
            textureRect[1] = pos[1]
            textureRect[3] = pos2[1]
        else:
            textureRect[1] = pos[1] + tilesize[1]
            textureRect[3] = -pos2[1]
        drawRect = self.getArea()

        return mainWindow.glwidget.createImage(self.texture, 1, textureRect, drawRect)

    def deleteTile(self):
        if self.tile:
            from rgeSystem import mainWindow
            mainWindow.glwidget.deleteImage(self.tile)
        self.tile = None


    def mousePressResponse(self, x, y, t):
        mapPosition = rgeSystem.getMapPosition((x, y))
        area = self.getArea()
        area[2] = area[0] + area[2]
        area[3] = area[1] + area[3]
        print mapPosition[0], mapPosition[1], area[0], area[1], area[2], area[3]
        if t == 0: #left click
            if mapPosition[0] >= area[0] and mapPosition[0] <= area[2]:
                if mapPosition[1] >= area[1] and mapPosition[1] <= area[3]:
                    self.beingDragged = True
                    self.dragX = mapPosition[0] - area[0]
                    self.dragY = mapPosition[1] - area[1]
                    rgeViews.spriteOffsetBothChanged(mapPosition[0] - self.dragX,mapPosition[1] - self.dragY)

    def mouseMoveResponse(self, x, y):
        if self.beingDragged:
            mapPosition = rgeSystem.getMapPosition((x, y))
            rgeViews.spriteOffsetBothChanged(mapPosition[0] - self.dragX,mapPosition[1] - self.dragY)

    def mouseReleaseResponse(self, x, y, t):
        self.beingDragged = False


#deprecated stuff below

class Sprite(object):

    '''EXAMPLE: Sprite("blah.png", (300, 300), (96, 96), (0, 1, 2, 3, 4), 50)
                Sprite.setAnim((0, 1, 2, 1), 30)
    '''

    def __init__(self, src, loc, framesize, initialanim, initialspeed):
        self.frame = framesize
        self.pos = loc
        self.textrect = (0, 0, framesize[0], framesize[1])
        self.drawrect = (loc[0], loc[1], framesize[0], framesize[1])
        self.img = rgeSystem.mainWindow.glwidget.createImage(src, 1, self.textrect, self.drawrect)
        self.setAnim(initialanim, initialspeed)

    def setAnim(self, anim, speed):
        self.currentanim = anim
        self.currentspeed = speed
        self.currentspot = 0
        self.tim = QtCore.QTimer()
        self.tim.timeout.connect(self.nextFrame)
        self.tim.start(self.currentspeed)

    def nextFrame(self):
        self.currentspot = (self.currentspot+1)%len(self.currentanim)
        self.img.displaceTextureRect((self.currentanim[self.currentspot]*self.frame[0], 0))

class Pog(object):

    def __init__(self, position, texturedimensions, size, layer, srcfile, status, locked, properties, alph):
        self.ID = None
        self._position = position
        self.texturedimensions = texturedimensions
        self._size = size
        self._layer = layer
        self._src = srcfile
        self.name = None
        self._tileStore = None
        self._fakeHidden = False
        self._properties = properties
        self._showTooltip = False
        self.tooltipId = -1
        self.alpha = alph
        self._locked = locked #locked only works for mouse movements. This means that scripts may actually be able to move the pog.
        self._tile = self._makeTile()
        if status > 0:
            self.hide()

    def destroy(self):
        if self._tileStore:
            self._tileStore.destroy()
            self._tileStore = None

    @property
    def hidden(self):
        return self._fakeHidden

    @property
    def status(self):
        if self._fakeHidden: return 1
        return 0

    @property
    def showTooltip(self):
        return self._showTooltip

    @showTooltip.setter
    def showTooltip(self, show):
        if self._showTooltip != show:
            if self.tooltipText() == None or len(self.tooltipText()) == 0:
                return
            from rgeSystem import mainWindow
            if show:
                self.tooltipId = mainWindow.glwidget.addText(self.tooltipText(), self._position)
            else:
                mainWindow.glwidget.removeText(self.tooltipId)
            self._showTooltip = show

    @property
    def position(self):
        return self._position

    @position.setter
    def position(self, position):
        self._position = position
        if not self.hidden:
            x, y = position
            if self._tile:
                self._tile.setX(x)
                self._tile.setY(y)
            if self._showTooltip:
                from rgeSystem import mainWindow
                mainWindow.glwidget.setTextPos(self.tooltipId, position)

    @property
    def _tile(self):
        return self._tileStore

    @_tile.setter
    def _tile(self, tile):
        if self._tileStore != None:
            self._tileStore.destroy()
        self._tileStore = tile

    @property
    def size(self):
        return self._size

    @property
    def properties(self):
        return self._properties

    @properties.setter
    def properties(self, properties):
        self._properties = properties

    @size.setter
    def size(self, size):
        self._size = size
        if self._tileStore:
            self._tileStore.setDrawW(size[0])
            self._tileStore.setDrawH(size[1])

    def editProperty(self, key, value):
        self._properties[key] = value
        if self._showTooltip:
            from rgeSystem import mainWindow
            mainWindow.glwidget.removeText(self.tooltipId)
            self.tooltipId = mainWindow.glwidget.addText(self.tooltipText(), self._position)

    def move(self, newloc):
        if self._locked:
            return self.position
        self.position = (newloc[0], newloc[1])
        return self.position

    def displace(self, displacement):
        if self._locked:
            return self.position

        self.position = map(lambda p,d: p + d, self.position, displacement)
        return self.position

    def hide(self):
        self._fakeHidden = True
        if self._tile:
            self._tile.setHidden(True)

    def show(self):
        self._fakeHidden = False
        if self._tile:
            self._tile.setHidden(False)

    def _realHide(self, hide):
        '''This makes the pog not redraw, but not necessarily hidden in a map.
           If a map hides and consecutively shows, we don't want previously hidden pogs to be shown.
        '''
        if self._tile:
            self._tile.setHidden(hide)

    @property
    def layer(self):
        return self._layer

    @layer.setter
    def layer(self, layer):
        self._layer = layer
        if not self.hidden:
            self._tile.layer = int(layer)

    @property
    def src(self):
        return self._src

    def pointCollides(self, point):
        if self.hidden: return False
        x, y = point
        sx, sy = self.position
        sw, sh = self.size
        if (sx > x or sx + sw < x or
            sy > y or sy + sh < y):
            return False
        return True

    def tooltipPosition(self):
        return self.position[0], self.position[1] - 20

    def tooltipText(self):
        self.atttmp = []
        if self.name is not None: self.atttmp.append(unicode(self.name))
        for key in self._properties:
            self.atttmp.append(": ".join([key, self._properties[key]]))
        if self.atttmp is not []:
            return "\n".join(self.atttmp)
        return None

    def deriveStringForm(self):
        self.tmp = [str(self.ID), str(self.x), str(self.y), str(self.w), str(self.h),
                             str(self.layer), str(self._src)]
        if self.name is not None:
            self.tmp.append(str(self.name))
        return " ".join(self.tmp)

    def _makeTile(self):
        from rgeSystem import mainWindow
        src = self._src
        textureRect = (0, 0, self.texturedimensions[0], self.texturedimensions[1])
        drawRect = (self.position[0], self.position[1], self.size[0], self.size[1])
        return mainWindow.glwidget.createImage(src, self.layer, textureRect, drawRect)

    def getSelectionCircleData(self):
        if self.alpha:
            return ((self.position[0]+self.size[0]/2, self.position[1]+self.size[1]/2, -1, (max(self.size[0], self.size[1])*1.2)/2))
        else:
            return ((self.position[0]+self.size[0]/2, self.position[1]+self.size[1]/2, -1, math.sqrt((self.size[0]**2)+(self.size[1]**2))/2))

    def forceUpdate(self):
        self._tile = self._makeTile()

    def dump(self):
        """Serialize to an object valid for JSON dumping."""
        return dict(
            position=self.position,
            texturedimensions=self.texturedimensions,
            size=self.size,
            layer=self.layer,
            src=self._src,
            name=self.name,
            status=self.status,
            locked=self._locked,
            properties=self.properties,
            alpha=self.alpha)

    @staticmethod
    def load(obj):
        """Deserialize a new pog from a dictionary."""
        pog = Pog(
            loadCoordinates('Pog.position', obj.get('position'), length=2),
            loadCoordinates('Pog.texturedimensions', obj.get('texturedimensions'), length=2, min=1, max=65535),
            loadCoordinates('Pog.size', obj.get('size'), length=2, min=1, max=65535),
            loadInteger('Pog.layer', obj.get('layer'), min=0, max=65535),
            loadString('Pog.src', obj.get('src')),
            loadInteger('Pog.status', obj.get('status')),
            loadInteger('Pog.locked', obj.get('locked')),
            loadObject('Pog.properties', obj.get('properties')),
            loadInteger('Pog.alpha', obj.get('alpha')))
        pog.name = loadString('Pog.name', obj.get('name'), allowEmpty=True)
        return pog